<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
	"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

<html>
<head>
<title>XLoadTree Implementation (WebFX)</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<script type="text/javascript" src="webfxlayout.local.js"></script>
</head>
<body>
<!-- WebFX Layout Include -->
<script type="text/javascript">

var articleMenu= new WebFXMenu;
articleMenu.left  = 384;
articleMenu.top   = 86;
articleMenu.width = 140;
articleMenu.add(new WebFXMenuItem("Introduction", "xloadtree.html"));
articleMenu.add(new WebFXMenuItem("Usage", "usage.html"));
articleMenu.add(new WebFXMenuItem("API", "api.html"));
articleMenu.add(new WebFXMenuItem("Implementation", "implementation.html"));
articleMenu.add(new WebFXMenuItem("Demo", "demo.html"));
articleMenu.add(new WebFXMenuSeparator);
articleMenu.add(new WebFXMenuItem("Download", "http://webfx.eae.net/download/xloadtree111.zip"));
webfxMenuBar.add(new WebFXMenuButton("Article Menu", null, null, articleMenu));

webfxLayout.writeTitle("XLoadTree");
webfxLayout.writeMenu();
webfxLayout.writeDesignedByEdger();

</script>
<div class="webfx-main-body">
<!-- end WebFX Layout Includes -->

<h2>Implementation</h2>

<p>The main idea is to create sub classes to <code>WebFXTree</code> and
<code>WebFXTreeItem</code> and overload the <code>expand</code> methods
to start the loading of an xml file. Once the loading is done the xml file
is tranformed into <code>WebFXTreeItem</code>s and <code>WebFXLoadTreeItem</code>s
and inserted.</p>

<h2>WebFXLoadTree</h2>

<p>First we create a new constructor and inside this we call the super constructor
to make sure that the instance will be correctly initiated. After that we set some
property values and finally we check whether the tree is open, if it is we start to
load the sub trees. If not, we add a dummy tree item that displays the loading
text.</p>

<p>After the constructor is created we set the protype to a new
<code>WebFXTree</code>.</p>

<pre>
function WebFXLoadTree(sText, sXmlSrc, sAction, sBehavior, sIcon, sOpenIcon) {
   // call super
   this.WebFXTree = WebFXTree;
   this.WebFXTree(sText, sAction, sBehavior, sIcon, sOpenIcon);

   // setup default property values
   this.src = sXmlSrc;
   this.loading = false;
   this.loaded = false;
   this.errorText = "";

   // check start state and load if open
   if (this.open)
      _startLoadXmlTree(this.src, this);
   else {
      // and create loading item if not
      this._loadingItem = new WebFXTreeItem(webFXTreeConfig.loadingText);
      this.add(this._loadingItem);
   }
}

WebFXLoadTree.prototype = new WebFXTree;
</pre>

<p>The constructor is fairly straight forward and does not do much. Notice however
how super is called by binding <code>WebFXTree</code> as a method and then
calling it.</p>

<p>Next we need to override the <code>expand</code> method but since we still need
to be able to call the original <code>expand</code> method we create a new method
called <code>_webfxtree_expand</code> that points to the function object used
by <code>WebFXTree</code> objects. This is the standard way to access super methods
but the first few times it might look a bit odd.</p>

<p>The logic in the <code>expand</code> method is really simple. We just check if
we should start loading the xml file and then we expand it using the super
expand (<code>_webfxtree_expand</code>) method.</p>

<pre>
// override the expand method to load the xml file
WebFXLoadTree.prototype._webfxtree_expand = WebFXTree.prototype.expand;
WebFXLoadTree.prototype.expand = function() {
   if (!this.loaded &amp;&amp; !this.loading) {
      // load
      _startLoadXmlTree(this.src, this);
   }
   this._webfxtree_expand();
};
</pre>

<h2>WebFXLoadTreeItem</h2>

<p>This class is too similar to <code>WebFXLoadTree</code> for me to be entirely
comfortable. Since JavaScript does not support multiple inheritance, and I did
not want to fake it using expandos, we just have to repeat the code. For everyone
that are interested, the code for this can be found in
<a href="xloadtree.js">xloadtree.js</a>.</p>

<h2>Loading the Tree</h2>

<p>As you can see in the code above there is a function called
<code>_startLoadXmlTree</code> that is called to load the actual xml file. This function uses
an <code>XmlHttp</code> object to do the actual loading. The loading of the xml
file is done asynchronously to prevent the UI to lock up while the file is
being loaded and therefore we wait for the <code>onreadystatechange</code>
event to fire before we continue. See the
<a href="/dhtml/xmlextras/xmlextras.html">Xml Extras article</a> for a more detailed
description about the <code>XmlHttp</code> object.</p>

<pre>
// creates the xmlhttp object and starts the load of the xml document
function _startLoadXmlTree(sSrc, jsNode) {
   jsNode.loading = true;
   var xmlHttp = XmlHttp.create();
   xmlHttp.open("GET", sSrc, true);	// async
   xmlHttp.onreadystatechange = function () {
      if (xmlHttp.readyState == 4)
         _xmlFileLoaded(xmlHttp.responseXML, jsNode);
   };
   // call in new thread to allow ui to update
   window.setTimeout(function () {
      xmlHttp.send(null);
   }, 10);
}
</pre>

<p>Once the xml file has finished loading we call the function <code>_xmlFileLoaded</code>.
This function checks that we got an xml document back and if we did it goes through the
document and recursively converts the xml elements to js <code>WebFXTreeItem</code> and
inserts them. Once the xml elements have been converted and inserted we remove the
dummy tree item that was only used to show that we were loading the contents.</p>

<pre>
// Inserts an xml document as a subtree to the provided node
function _xmlFileLoaded(oXmlDoc, jsParentNode) {
   var bIndent = false;
   var bAnyChildren = false;
   jsParentNode.loaded = true;
   jsParentNode.loading = false;

   // check that the load of the xml file went well
   if( oXmlDoc == null || oXmlDoc.documentElement == null) {
      jsParentNode.errorText = parseTemplateString(webFXTreeConfig.loadErrorTextTemplate,
                                                   jsParentNode.src);
   }
   else {
      // there is one extra level of tree elements
      var root = oXmlDoc.documentElement;

      // loop through all tree children
      var cs = root.childNodes;
      var l = cs.length;
      for (var i = 0; i &lt; l; i++) {
         if (cs[i].tagName == "tree") {
            bAnyChildren = true;
            bIndent = true;
            jsParentNode.add( _xmlTreeToJsTree(cs[i]), true);
         }
      }

      // if no children we got an error
      if (!bAnyChildren)
         jsParentNode.errorText = parseTemplateString(webFXTreeConfig.emptyErrorTextTemplate,
                                                      jsParentNode.src);
   }

   // remove dummy
   if (jsParentNode._loadingItem != null) {
      jsParentNode._loadingItem.remove();
      bIndent = true;
   }

   if (bIndent) {
      // indent now that all items are added
      jsParentNode.indent();
   }

   // show error in status bar
   if (jsParentNode.errorText != "")
      window.status = jsParentNode.errorText;
}
</pre>

<p>A few more things happen in this function but nothing really important. There is some
code that checks the errors and a few properties are set to reflect the state of the
<code>WebFXLoadTree</code> or <code>WebFXLoadTreeItem</code> object.</p>

<h2>Converting the Xml</h2>

<p>The only important thing left to do is to convert the xml tree item to a js
<code>WebFXTreeItem</code>. This is done in the function <code>_xmlTreeToJsTree</code>.
Here we retreive the xml attributes and if there was a <code>src</code> attribute
defined we create a new <code>WebFXLoadTreeItem</code> and otherwise a
<code>WebFXTreeItem</code>. Once that is created we go through all the
<code>childNodes</code> of the xml node and convert and add those as well.</p>

<pre>
// Converts an xml tree to a js tree. See article about xml tree format
function _xmlTreeToJsTree(oNode) {
	// retreive attributes
   var text = oNode.getAttribute("text");
   var action = oNode.getAttribute("action");
   var parent = null;
   var icon = oNode.getAttribute("icon");
   var openIcon = oNode.getAttribute("openIcon");
   var src = oNode.getAttribute("src");

   // create jsNode
   var jsNode;
   if (src != null &amp;&amp; src != "")
      jsNode = new WebFXLoadTreeItem(text, src, action, parent, icon, openIcon);
   else
      jsNode = new WebFXTreeItem(text, action, parent, icon, openIcon);

   // go through childNOdes
   var cs = oNode.childNodes;
   var l = cs.length;
   for (var i = 0; i &lt; l; i++) {
      if (cs[i].tagName == "tree")
         jsNode.add( _xmlTreeToJsTree(cs[i]), true );
   }

   return jsNode;
}
</pre>


<p>
<a href="xloadtree.html">Introduction</a><br />
<a href="usage.html">Usage</a><br />
<a href="api.html">API</a><br />
<a href="implementation.html">Implementation</a><br />
<a href="demo.html">Demo</a><br />
<a href="http://webfx.eae.net/download/xloadtree111.zip">Download</a>
</p>

<p class="author">Author: Erik Arvidsson</p>

<!-- end webfx-main-body -->
</div>

</body>
</html>
